/**\file gu_material_slot.h*/
#pragma once

#include "gu_shader_adapter.h"
#include "gu_shader_variable.h"
#include "gu_vertex_buffer.h"
#include "gu_stream_map.h"
#include "gu_renderer.h"

#include<memory>
#include<map>
#include<cassert>

namespace gu {

/**
    MaterialSlot:
        - binds a shader, material and geometry streams to a renderable context.
        - maps the bound RenderMesh to the stream map of the attached shader adapter.

*/

// TODO: add shader reference.

class MaterialSlot
{
#if 0
    enum SlotType{VERTEX, INDEX, UNIFORM};



    struct Slot
    {
        SlotType kind;
        union
        {
            struct{std::string name; bool assigned;} uniform;
            struct{TypeMapping mapping; VariableType} stream;
            struct{bool alloced;} indices;
        } data;
        VariableType type;
    };

    // Local values - all uniforms have local data attached to them.
    // TODO: Should streams have default streams attached to them as well
    std::map<const char*, Slot> uniforms_;
    std::map<const char*, Slot> streams_;
#endif

    ShaderAdapter shaderAdapter_;
    Renderer&     renderer_;
public:

    MaterialSlot(Renderer& renderer):shaderAdapter_(renderer.getShaderAdapter()), renderer_(renderer)
    {
    }

    bool mapBuffers(VertexBuffer* vertexBuffer, IndexBuffer* indexBuffer)
    {
        bool result = false;
        if(vertexBuffer && indexBuffer)
        {
            StreamMap* streamMap = shaderAdapter_.streamMap();
            streamMap->vertexBuffer(vertexBuffer);
            streamMap->indexBuffer(indexBuffer);
            result = true;
        }
        else
        {
            assert(!"Tried to bind null buffer!");
        }
        return result;
    }

    void map(const char* name, float* data)
    {
    }

    // TODO: use -> transfers data to uniformMap and streamMap ??
    // Toplevel rendering will go through scene graph, 
    // using and rendering material slots as they come along

    void render()
    {
        auto uniformMap = shaderAdapter_.uniformMap();
        auto streamMap = shaderAdapter_.streamMap();

        // TODO: Add some way to check that shader has all uniforms transferred.

        if(streamMap->attached())
        {
            // Use shader unless renderer active shader is same
                // if calling use shader reset all uniform updates
            // Transfer uniforms  that require update, set their update state to not needed
            // todo: how to transfer engine uniforms? A list of pointers to reference values (do not want to replicate
            // same data over and over and over again )
            streamMap->render();
        }
        else
        {
            assert(!"Streams or uniforms not attached");
        }
    }
};

typedef std::shared_ptr<MaterialSlot> MaterialSlotPtr;

MaterialSlot* newMaterialSlot(Renderer& renderer);

}
